var VSHADER_SOURCE =
    'attribute vec4 a_Position;\n' +
    'attribute vec4 a_Color;\n' + //物体颜色
    'attribute vec4 a_Normal;\n' + //法向量
    'uniform mat4 u_MvpMatrix;\n' + //模型视图投影矩阵
    'uniform mat4 u_ModelMatrix;\n' + // 模型矩阵
    'uniform mat4 u_NormalMatrix;\n' + // 法向量变换矩阵
    'varying vec4 v_Color;\n' +
    'varying vec3 v_Normal;\n' +
    'varying vec3 v_Position;\n' +
    'void main() {\n' +
    '  gl_Position = u_MvpMatrix * a_Position;\n' +
    // 计算世界坐标下的定点坐标
    '  v_Position = vec3(u_ModelMatrix * a_Position);\n' +
    '  v_Normal = normalize(vec3(u_NormalMatrix * a_Normal));\n' +
    '  v_Color = a_Color;\n' +
    '}\n';

// Fragment shader program
var FSHADER_SOURCE =
    '#ifdef GL_ES\n' +
    'precision mediump float;\n' +
    '#endif\n' +
    'uniform vec3 u_LightColor;\n' + // 光照颜色
    'uniform vec3 u_LightPosition;\n' + // 光的位置
    'uniform vec3 u_AmbientLight;\n' + // 环境光的颜色
    'varying vec3 v_Normal;\n' +
    'varying vec3 v_Position;\n' +
    'varying vec4 v_Color;\n' +
    'void main() {\n' +
    // 对法线进行归一化
    '  vec3 normal = normalize(v_Normal);\n' +
    // 计算光线方向并归一化
    '  vec3 lightDirection = normalize(u_LightPosition - v_Position);\n' +
    // 计算光线方向和法向量的点积
    '  float nDotL = max(dot(lightDirection, normal), 0.0);\n' +
    // 计算光照效果和环境光照效果
    '  vec3 diffuse = u_LightColor * v_Color.rgb * nDotL;\n' +
    '  vec3 ambient = u_AmbientLight * v_Color.rgb;\n' +
    //计算最终光照效果
    '  gl_FragColor = vec4(diffuse + ambient, v_Color.a);\n' +
    '}\n';
//
// function draw3D(opt_src) {
//     draw3D.eye = (0.0, 0.0, 14);
// };

function main() {

    var canvas = document.getElementById('cylinder');

    var gl = WebGLUtils.setupWebGL(canvas);
    if (!gl) {
        console.log('Failed to get the rendering context for WebGL');
        return;
    }


    gl.clearColor(0.0, 0.0, 0.0, 0.0);
    gl.enable(gl.DEPTH_TEST);
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

    drawCylinder([0.0, 1.0, 0.0, 1.0], [0.0, -1.0, 0.0, 1.0], 1, [1.0, 0.0, 0.0], gl);
    // gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

    // drawCylinder([2.0, 0.0, 0.0, 1.0], [3.0, 0.0, 0.0, 1.0], 0.5, [1.0, 0.0, 0.0], gl);
    updateCylinder([1.0, 1.0, 0.0, 1.0], [1.0, -1.0, 0.0, 1.0], gl);
}


var Eye = new Array(0, 0, 14);


var MODEL_MATRIX = new Matrix4();


function setEye(eyeX, eyeY, eyeZ) {
    Eye[0] = eyeX;
    Eye[1] = eyeY;
    Eye[2] = eyeZ;
}

function setModelMatrix(modelMatrix) {
    MODEL_MATRIX = modelMatrix;
}


/**
 * 画圆柱，
 * vertice1 上圆心
 * vertice2 下圆心
 * r 半径 
 * colors 颜色
 * gl
 */
var n;

function drawCylinder(vertice1, vertice2, r, colors, gl) {

    if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
        console.log('Failed to intialize shaders.');
        return;
    }

    //圆柱的上下两点的向量
    var vector2_1 = new Array(3);
    //从原点到圆柱中心的向量 = 上下圆心的中点坐标
    var vector0_c = new Array(3);

    for (var i = 0; i < vector2_1.length; i++) {
        vector2_1[i] = vertice1[i] / vertice1[3] - vertice2[i] / vertice2[3];
        vector0_c[i] = (vertice1[i] / vertice1[3] + vertice2[i] / vertice2[3]) / 2;
    }
    // console.log(vector0_c);

    var high = Math.sqrt(vector2_1[0] * vector2_1[0] + vector2_1[1] * vector2_1[1] + vector2_1[2] * vector2_1[2]);
    // console.log(high);
    // 上下两个圆面的y坐标
    var y1 = high / 2;
    var y2 = (-1) * high / 2;

    //变换矩阵
    var modelMatrix = new Matrix4();
    var a_zx;
    var a_z;;
    if (vector2_1[0] == 0) {
        a_zx = Math.PI / 2;
        if (vector2_1[2] < 0) {
            a_zx = a_zx * (-1);
        }
    } else {
        if (vector2_1[2] == 0) {
            if (vector2_1[0] > 0) {
                a_zx = 0;
            } else {
                a_zx = Math.PI;
            }

        } else {
            a_zx = Math.atan(vector2_1[2] / vector2_1[0]);
            if (vector2_1[0] < 0) {
                a_zx += Math.PI;
            }
        }
    }

    var x_y_z = Math.sqrt(vector2_1[0] * vector2_1[0] + vector2_1[1] * vector2_1[1] + vector2_1[2] * vector2_1[2]);
    if (vector2_1[1] == 0) {
        a_z = Math.PI / 2;
    } else {
        a_z = Math.acos(vector2_1[1] / x_y_z);
    }
    // console.log(180 * a_Z / Math.PI);
    // console.log(180 * a_Y / Math.PI);

    modelMatrix.setTranslate(0, 0, 0);

    modelMatrix.multiply(MODEL_MATRIX);

    modelMatrix.translate(vector0_c[0], vector0_c[1], vector0_c[2]);
    modelMatrix.rotate(180 * a_zx / Math.PI, 0, 1, 0);
    modelMatrix.rotate(180 * a_z / Math.PI, 0, 0, 1);
    modelMatrix.rotate((-1) * 180 * a_zx / Math.PI, 0, 1, 0);


    // console.log(modelMatrix.elements);
    //初始化缓存区
    n = cylinderInitVertexBuffers(gl, y1, y2, r, colors);
    if (n < 0) {
        console.log('Failed to set the vertex information');
        return;
    }

    // gl.clearColor(0.0, 0.0, 0.0, 1.0);
    // gl.enable(gl.DEPTH_TEST);



    var u_ModelMatrix = gl.getUniformLocation(gl.program, 'u_ModelMatrix');
    var u_MvpMatrix = gl.getUniformLocation(gl.program, 'u_MvpMatrix');
    var u_NormalMatrix = gl.getUniformLocation(gl.program, 'u_NormalMatrix');
    var u_LightColor = gl.getUniformLocation(gl.program, 'u_LightColor');
    var u_LightPosition = gl.getUniformLocation(gl.program, 'u_LightPosition');
    var u_AmbientLight = gl.getUniformLocation(gl.program, 'u_AmbientLight');
    if (!u_ModelMatrix || !u_MvpMatrix || !u_NormalMatrix || !u_LightColor || !u_LightPosition || !u_AmbientLight) {
        console.log('Failed to get the storage location');
        return;
    }

    // 设置光照颜色 (white)
    gl.uniform3f(u_LightColor, 1.0, 1.0, 1.0);
    // 光位置 (in the world coordinate)
    gl.uniform3f(u_LightPosition, 2.3, 4.0, 3.5);
    // 环境光
    gl.uniform3f(u_AmbientLight, 0.2, 0.2, 0.2);


    var mvpMatrix = new Matrix4();
    var normalMatrix = new Matrix4();

    mvpMatrix.setPerspective(30, 1, 1, 100);
    mvpMatrix.lookAt(Eye[0], Eye[1], Eye[2], 0, 0, 0, 0, 1, 0);

    mvpMatrix.multiply(modelMatrix);

    normalMatrix.setInverseOf(modelMatrix);
    normalMatrix.transpose();

    gl.uniformMatrix4fv(u_ModelMatrix, false, modelMatrix.elements);

    gl.uniformMatrix4fv(u_MvpMatrix, false, mvpMatrix.elements);

    gl.uniformMatrix4fv(u_NormalMatrix, false, normalMatrix.elements);
    // gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
    gl.drawElements(gl.TRIANGLES, n, gl.UNSIGNED_SHORT, 0);
}

function updateCylinder(vertice1, vertice2, gl) {
    //圆柱的上下两点的向量
    var vector2_1 = new Array(3);
    //从原点到圆柱中心的向量 = 上下圆心的中点坐标
    var vector0_c = new Array(3);
    for (var i = 0; i < vector2_1.length; i++) {
        vector2_1[i] = vertice1[i] / vertice1[3] - vertice2[i] / vertice2[3];
        vector0_c[i] = (vertice1[i] / vertice1[3] + vertice2[i] / vertice2[3]) / 2;
    }

    //变换矩阵
    var modelMatrix = new Matrix4();
    var a_zx;
    var a_z;;
    if (vector2_1[0] == 0) {
        a_zx = Math.PI / 2;
        if (vector2_1[2] < 0) {
            a_zx = a_zx * (-1);
        }
    } else {
        if (vector2_1[2] == 0) {
            if (vector2_1[0] > 0) {
                a_zx = 0;
            } else {
                a_zx = Math.PI;
            }

        } else {
            a_zx = Math.atan(vector2_1[2] / vector2_1[0]);
            if (vector2_1[0] < 0) {
                a_zx += Math.PI;
            }
        }
    }

    var x_y_z = Math.sqrt(vector2_1[0] * vector2_1[0] + vector2_1[1] * vector2_1[1] + vector2_1[2] * vector2_1[2]);
    if (vector2_1[1] == 0) {
        a_z = Math.PI / 2;
    } else {
        a_z = Math.acos(vector2_1[1] / x_y_z);
    }
    // console.log(180 * a_Z / Math.PI);
    // console.log(180 * a_Y / Math.PI);

    modelMatrix.setTranslate(0, 0, 0);

    modelMatrix.multiply(MODEL_MATRIX);

    modelMatrix.translate(vector0_c[0], vector0_c[1], vector0_c[2]);
    modelMatrix.rotate(180 * a_zx / Math.PI, 0, 1, 0);
    modelMatrix.rotate(180 * a_z / Math.PI, 0, 0, 1);
    modelMatrix.rotate((-1) * 180 * a_zx / Math.PI, 0, 1, 0);

    var u_ModelMatrix = gl.getUniformLocation(gl.program, 'u_ModelMatrix');
    var u_MvpMatrix = gl.getUniformLocation(gl.program, 'u_MvpMatrix');
    var u_NormalMatrix = gl.getUniformLocation(gl.program, 'u_NormalMatrix');
    if (!u_ModelMatrix || !u_MvpMatrix || !u_NormalMatrix) {
        console.log('Failed to get the storage location');
        return;
    }

    var mvpMatrix = new Matrix4();
    var normalMatrix = new Matrix4();

    mvpMatrix.setPerspective(30, 1, 1, 100);
    mvpMatrix.lookAt(Eye[0], Eye[1], Eye[2], 0, 0, 0, 0, 1, 0);

    mvpMatrix.multiply(modelMatrix);

    normalMatrix.setInverseOf(modelMatrix);
    normalMatrix.transpose();

    gl.uniformMatrix4fv(u_ModelMatrix, false, modelMatrix.elements);

    gl.uniformMatrix4fv(u_MvpMatrix, false, mvpMatrix.elements);
    console.log("hello");
    gl.uniformMatrix4fv(u_NormalMatrix, false, normalMatrix.elements);
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
    gl.drawElements(gl.TRIANGLES, n, gl.UNSIGNED_SHORT, 0);
}

function cylinderInitVertexBuffers(gl, y1, y2, r, color) {

    var num = 240; //一个园面的扇形数
    var vertice_num = ((num + 1) * 3 + 1) * 2; //点数量
    //点位置
    var vertices = new Float32Array(vertice_num * 3);
    //点颜色
    var colors = new Float32Array(vertice_num * 3);
    //法向量
    var normals = new Float32Array(vertice_num * 3);
    //点索引
    var indices = new Uint16Array(num * 4 * 3);


    //计算圆上的点
    //上下两个圆面的圆心
    var index = 0;
    var tmpVertice = new Array();
    var tmpNormal1 = new Array();
    var tmpNormal2 = new Array();
    tmpVertice[0] = 0;
    tmpVertice[1] = y1;
    tmpVertice[2] = 0;
    vertices.set(tmpVertice, index);
    colors.set(color, index);
    normals.set([0, 1, 0], index);
    index += 3;

    tmpVertice[1] = y2;
    vertices.set(tmpVertice, index);
    colors.set(color, index);
    normals.set([0, -1, 0], index);
    index += 3;

    //圆上的点
    var aa = 0;
    var a = (1 / num) * Math.PI;
    tmpNormal1[1] = 0;
    tmpNormal2[1] = 0;
    for (var i = 0; i < num + 1; i++) {

        aa = (i / num) * 2 * Math.PI;
        tmpNormal1[0] = Math.cos(aa - a);
        tmpNormal1[2] = Math.sin(aa - a);
        tmpNormal2[0] = Math.cos(aa + a);
        tmpNormal2[2] = Math.sin(aa + a);

        tmpVertice[0] = r * Math.cos(aa);
        tmpVertice[1] = y1;
        tmpVertice[2] = r * Math.sin(aa);


        vertices.set(tmpVertice, index);
        colors.set(color, index);
        normals.set(tmpNormal1, index);
        index += 3;
        vertices.set(tmpVertice, index);
        colors.set(color, index);
        normals.set([0, 1, 0], index);
        index += 3;
        vertices.set(tmpVertice, index);
        colors.set(color, index);
        normals.set(tmpNormal2, index);
        index += 3;

        tmpVertice[1] = y2;
        vertices.set(tmpVertice, index);
        colors.set(color, index);
        normals.set(tmpNormal1, index);
        index += 3;
        vertices.set(tmpVertice, index);
        colors.set(color, index);
        normals.set([0, -1, 0], index);
        index += 3;
        vertices.set(tmpVertice, index);
        colors.set(color, index);
        normals.set(tmpNormal2, index);
        index += 3;

    }

    //计算三角形的组合
    var index = 0;
    var tIndices = new Array(3);

    for (var i = 3; i < vertice_num - 6; i += 6) {
        tIndices[0] = 0;
        tIndices[1] = i;
        tIndices[2] = i + 6;
        indices.set(tIndices, index);
        index += 3;

        tIndices[0] = i + 1;
        tIndices[1] = i + 4;
        tIndices[2] = i + 5;
        indices.set(tIndices, index);
        index += 3;

        tIndices[0] = i + 4;
        tIndices[1] = i + 5;
        tIndices[2] = i + 8;
        indices.set(tIndices, index);
        index += 3;

        tIndices[0] = 1;
        tIndices[1] = i + 3;
        tIndices[2] = i + 9;
        indices.set(tIndices, index);
        index += 3;
    }


    if (!initArrayBuffer(gl, 'a_Position', vertices, 3)) return -1;
    if (!initArrayBuffer(gl, 'a_Color', colors, 3)) return -1;
    if (!initArrayBuffer(gl, 'a_Normal', normals, 3)) return -1;

    // Unbind the buffer object
    gl.bindBuffer(gl.ARRAY_BUFFER, null);

    // Write the indices to the buffer object
    var indexBuffer = gl.createBuffer();
    if (!indexBuffer) {
        console.log('Failed to create the buffer object');
        return false;
    }
    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
    gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);

    return indices.length;
}

/**
 * [drawBall 画球]
 * @param  {四元数组} vertice1 球心坐标
 * @param  {三元数组} vector 球的上方向
 * @param  {数值} half    为0.5时为半球,为1时为整球
 * @param  {数值} r       球半径
 * @param  {[三元数组]} colors  球颜色
 * @param  {[type]} gl      [description]
 */
function drawBall(vertice, vector, half, r, colors, gl) {

    if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
        console.log('Failed to intialize shaders.');
        return;
    }

    var modelMatrix = new Matrix4();
    var a_zx;
    var a_z;;
    if (vector[0] == 0) {
        a_zx = Math.PI / 2;
        if (vector[2] < 0) {
            a_zx = a_zx * (-1);
        }
    } else {
        if (vector[2] == 0) {
            if (vector[0] > 0) {
                a_zx = 0;
            } else {
                a_zx = Math.PI;
            }

        } else {
            a_zx = Math.atan(vector[2] / vector[0]);
            if (vector[0] < 0) {
                a_zx += Math.PI;
            }
        }
    }
    var x_y_z = Math.sqrt(vector[0] * vector[0] + vector[1] * vector[1] + vector[2] * vector[2]);
    if (vector[1] == 0) {
        a_z = Math.PI / 2;
    } else {
        a_z = Math.acos(vector[1] / x_y_z);
    }


    modelMatrix.setTranslate(0, 0, 0);

    modelMatrix.multiply(MODEL_MATRIX);

    modelMatrix.translate(vertice[0], vertice[1], vertice[2]);
    modelMatrix.rotate(180 * a_zx / Math.PI, 0, 1, 0);
    modelMatrix.rotate(180 * a_z / Math.PI, 0, 0, 1);
    modelMatrix.rotate((-1) * 180 * a_zx / Math.PI, 0, 1, 0);

    //初始化缓存区
    var n = ballInitVertexBuffers(gl, half, r, colors);
    if (n < 0) {
        console.log('Failed to set the vertex information');
        return;
    }

    var u_ModelMatrix = gl.getUniformLocation(gl.program, 'u_ModelMatrix');
    var u_MvpMatrix = gl.getUniformLocation(gl.program, 'u_MvpMatrix');
    var u_NormalMatrix = gl.getUniformLocation(gl.program, 'u_NormalMatrix');
    var u_LightColor = gl.getUniformLocation(gl.program, 'u_LightColor');
    var u_LightPosition = gl.getUniformLocation(gl.program, 'u_LightPosition');
    var u_AmbientLight = gl.getUniformLocation(gl.program, 'u_AmbientLight');
    if (!u_ModelMatrix || !u_MvpMatrix || !u_NormalMatrix || !u_LightColor || !u_LightPosition || !u_AmbientLight) {
        console.log('Failed to get the storage location');
        return;
    }

    // 设置光照颜色 (white)
    gl.uniform3f(u_LightColor, 1.0, 1.0, 1.0);
    // 光位置 (in the world coordinate)
    gl.uniform3f(u_LightPosition, 2.3, 4.0, 3.5);
    // 环境光
    gl.uniform3f(u_AmbientLight, 0.2, 0.2, 0.2);


    var mvpMatrix = new Matrix4();
    var normalMatrix = new Matrix4();

    mvpMatrix.setPerspective(30, 1, 1, 100);
    mvpMatrix.lookAt(Eye[0], Eye[1], Eye[2], 0, 0, 0, 0, 1, 0);

    mvpMatrix.multiply(modelMatrix);

    normalMatrix.setInverseOf(modelMatrix);
    normalMatrix.transpose();

    gl.uniformMatrix4fv(u_ModelMatrix, false, modelMatrix.elements);

    gl.uniformMatrix4fv(u_MvpMatrix, false, mvpMatrix.elements);

    gl.uniformMatrix4fv(u_NormalMatrix, false, normalMatrix.elements);
    // gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
    gl.drawElements(gl.TRIANGLES, n, gl.UNSIGNED_SHORT, 0);
}

function ballInitVertexBuffers(gl, half, r, color) {

    var SPHERE_DIV = 26;
    var colors = new Float32Array((SPHERE_DIV + 1) * (SPHERE_DIV + 1) * 3);
    var i, ai, si, ci;
    var j, aj, sj, cj;
    var p1, p2;

    var positions = [];
    var indices = [];


    var index = 0;
    // Generate coordinates
    for (j = 0; j <= SPHERE_DIV; j++) {
        aj = j * Math.PI * half / SPHERE_DIV;
        sj = r * Math.sin(aj);
        cj = r * Math.cos(aj);
        for (i = 0; i <= SPHERE_DIV; i++) {
            ai = i * 2 * Math.PI / SPHERE_DIV;
            si = Math.sin(ai);
            ci = Math.cos(ai);

            positions.push(si * sj); // X
            positions.push(cj); // Y
            positions.push(ci * sj); // Z

            colors.set(color, index);
            index += 3;
        }
    }

    // Generate indices
    for (j = 0; j < SPHERE_DIV; j++) {
        for (i = 0; i < SPHERE_DIV; i++) {
            p1 = j * (SPHERE_DIV + 1) + i;
            p2 = p1 + (SPHERE_DIV + 1);

            indices.push(p1);
            indices.push(p2);
            indices.push(p1 + 1);

            indices.push(p1 + 1);
            indices.push(p2);
            indices.push(p2 + 1);
        }
    }


    if (!initArrayBuffer(gl, 'a_Position', new Float32Array(positions), 3)) return -1;
    if (!initArrayBuffer(gl, 'a_Color', colors, 3)) return -1;
    if (!initArrayBuffer(gl, 'a_Normal', new Float32Array(positions), 3)) return -1;


    gl.bindBuffer(gl.ARRAY_BUFFER, null);


    var indexBuffer = gl.createBuffer();
    if (!indexBuffer) {
        console.log('Failed to create the buffer object');
        return false;
    }
    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
    gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);

    return indices.length;
}

function initArrayBuffer(gl, attribute, data, num) {
    // Create a buffer object
    var buffer = gl.createBuffer();
    if (!buffer) {
        console.log('Failed to create the buffer object');
        return false;
    }
    // Write date into the buffer object
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
    gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);
    // Assign the buffer object to the attribute variable
    var a_attribute = gl.getAttribLocation(gl.program, attribute);
    if (a_attribute < 0) {
        console.log('Failed to get the storage location of ' + attribute);
        return false;
    }
    gl.vertexAttribPointer(a_attribute, num, gl.FLOAT, false, 0, 0);
    // Enable the assignment of the buffer object to the attribute variable
    gl.enableVertexAttribArray(a_attribute);

    return true;
}